<template>
  <div class="file-upload-container">
    <el-upload
      ref="uploadRef"
      :action="uploadUrl"
      :headers="uploadHeaders"
      :data="uploadData"
      :file-list="fileList"
      :multiple="multiple"
      :accept="accept"
      :limit="limit"
      :before-upload="beforeUpload"
      :on-success="handleSuccess"
      :on-error="handleError"
      :on-remove="handleRemove"
      :on-exceed="handleExceed"
      :on-preview="handlePreview"
      :disabled="disabled"
      :drag="drag"
      :show-file-list="showFileList"
      :list-type="listType"
      class="upload-component"
    >
      <template v-if="drag">
        <div class="drag-upload-area">
          <Icon icon="ep:upload-filled" class="text-4xl text-gray-400 mb-2" />
          <div class="text-gray-600">将文件拖到此处，或<em>点击上传</em></div>
          <div class="text-gray-400 text-sm mt-2" v-if="tip">{{ tip }}</div>
        </div>
      </template>
      <template v-else>
        <el-button type="primary" :disabled="disabled">
          <Icon icon="ep:upload" class="mr-1" />
          {{ buttonText }}
        </el-button>
        <div class="text-gray-400 text-sm mt-2" v-if="tip">{{ tip }}</div>
      </template>
    </el-upload>

    <!-- 文件预览弹窗 -->
    <el-dialog
      v-model="previewVisible"
      title="文件预览"
      width="60%"
      :before-close="handlePreviewClose"
    >
      <div v-if="previewFile">
        <!-- 图片预览 -->
        <div v-if="isImage(previewFile.name)" class="text-center">
          <img :src="previewFile.url" alt="预览图片" style="max-width: 100%; max-height: 500px;" />
        </div>
        
        <!-- PDF预览 -->
        <div v-else-if="isPdf(previewFile.name)" class="text-center">
          <iframe :src="previewFile.url" width="100%" height="500px" frameborder="0"></iframe>
        </div>
        
        <!-- 其他文件类型 -->
        <div v-else class="text-center py-8">
          <Icon icon="ep:document" class="text-6xl text-gray-400 mb-4" />
          <div class="text-gray-600">{{ previewFile.name }}</div>
          <div class="text-gray-400 text-sm mt-2">此文件类型不支持预览</div>
          <el-button type="primary" @click="downloadFile(previewFile)" class="mt-4">
            <Icon icon="ep:download" class="mr-1" />
            下载文件
          </el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { getAccessToken } from '@/utils/auth'
import { formatFileSize } from '@/utils/eval'

interface Props {
  /** 上传地址 */
  action?: string
  /** 文件列表 */
  modelValue?: any[]
  /** 是否支持多选 */
  multiple?: boolean
  /** 接受的文件类型 */
  accept?: string
  /** 最大上传数量 */
  limit?: number
  /** 最大文件大小(MB) */
  maxSize?: number
  /** 是否禁用 */
  disabled?: boolean
  /** 是否支持拖拽上传 */
  drag?: boolean
  /** 是否显示文件列表 */
  showFileList?: boolean
  /** 列表类型 */
  listType?: 'text' | 'picture' | 'picture-card'
  /** 按钮文本 */
  buttonText?: string
  /** 提示文本 */
  tip?: string
  /** 上传额外参数 */
  data?: Record<string, any>
}

const props = withDefaults(defineProps<Props>(), {
  action: '/admin-api/infra/file/upload',
  modelValue: () => [],
  multiple: false,
  accept: '*',
  limit: 5,
  maxSize: 10,
  disabled: false,
  drag: false,
  showFileList: true,
  listType: 'text',
  buttonText: '选择文件',
  tip: '',
  data: () => ({})
})

const emit = defineEmits<{
  'update:modelValue': [files: any[]]
  'success': [file: any, fileList: any[]]
  'error': [error: any, file: any, fileList: any[]]
  'remove': [file: any, fileList: any[]]
}>()

const uploadRef = ref()
const fileList = ref<any[]>([])
const previewVisible = ref(false)
const previewFile = ref<any>(null)

/** 上传地址 */
const uploadUrl = computed(() => {
  return import.meta.env.VITE_BASE_URL + props.action
})

/** 上传请求头 */
const uploadHeaders = computed(() => {
  return {
    Authorization: 'Bearer ' + getAccessToken()
  }
})

/** 上传参数 */
const uploadData = computed(() => {
  return {
    ...props.data
  }
})

/** 监听文件列表变化 */
watch(
  () => props.modelValue,
  (newVal) => {
    fileList.value = newVal || []
  },
  { immediate: true, deep: true }
)

/** 上传前检查 */
const beforeUpload = (file: File) => {
  // 检查文件大小
  if (props.maxSize && file.size > props.maxSize * 1024 * 1024) {
    ElMessage.error(`文件大小不能超过 ${props.maxSize}MB`)
    return false
  }

  // 检查文件类型
  if (props.accept !== '*') {
    const acceptTypes = props.accept.split(',').map(type => type.trim())
    const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase()
    const isAccepted = acceptTypes.some(type => {
      if (type.startsWith('.')) {
        return type === fileExtension
      } else if (type.includes('/')) {
        return file.type === type
      }
      return false
    })
    
    if (!isAccepted) {
      ElMessage.error(`只能上传 ${props.accept} 格式的文件`)
      return false
    }
  }

  return true
}

/** 上传成功 */
const handleSuccess = (response: any, file: any, fileList: any[]) => {
  if (response.code === 0) {
    const newFile = {
      name: file.name,
      url: response.data,
      size: file.size,
      type: file.type,
      uid: file.uid
    }
    
    const updatedList = [...fileList.value, newFile]
    fileList.value = updatedList
    emit('update:modelValue', updatedList)
    emit('success', newFile, updatedList)
    
    ElMessage.success('上传成功')
  } else {
    ElMessage.error(response.msg || '上传失败')
    emit('error', response, file, fileList)
  }
}

/** 上传失败 */
const handleError = (error: any, file: any, fileList: any[]) => {
  ElMessage.error('上传失败')
  emit('error', error, file, fileList)
}

/** 移除文件 */
const handleRemove = (file: any, fileList: any[]) => {
  const updatedList = fileList.filter(item => item.uid !== file.uid)
  emit('update:modelValue', updatedList)
  emit('remove', file, updatedList)
}

/** 超出限制 */
const handleExceed = (files: any[], fileList: any[]) => {
  ElMessage.warning(`最多只能上传 ${props.limit} 个文件`)
}

/** 预览文件 */
const handlePreview = (file: any) => {
  previewFile.value = file
  previewVisible.value = true
}

/** 关闭预览 */
const handlePreviewClose = () => {
  previewVisible.value = false
  previewFile.value = null
}

/** 判断是否为图片 */
const isImage = (fileName: string) => {
  const imageTypes = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
  const extension = '.' + fileName.split('.').pop()?.toLowerCase()
  return imageTypes.includes(extension)
}

/** 判断是否为PDF */
const isPdf = (fileName: string) => {
  return fileName.toLowerCase().endsWith('.pdf')
}

/** 下载文件 */
const downloadFile = (file: any) => {
  const link = document.createElement('a')
  link.href = file.url
  link.download = file.name
  link.click()
}

/** 清空文件列表 */
const clearFiles = () => {
  uploadRef.value?.clearFiles()
  fileList.value = []
  emit('update:modelValue', [])
}

/** 手动上传 */
const submit = () => {
  uploadRef.value?.submit()
}

/** 暴露方法 */
defineExpose({
  clearFiles,
  submit
})
</script>

<style scoped>
.file-upload-container {
  width: 100%;
}

.drag-upload-area {
  padding: 40px;
  text-align: center;
  border: 2px dashed #d9d9d9;
  border-radius: 6px;
  background-color: #fafafa;
  transition: border-color 0.3s;
}

.drag-upload-area:hover {
  border-color: #409eff;
}

.upload-component :deep(.el-upload-dragger) {
  border: none;
  background: none;
  padding: 0;
}

.upload-component :deep(.el-upload-dragger:hover) {
  border-color: #409eff;
}
</style>
